#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include "usocket.h"
#include "umessage.h"
#include "userver.h"


#define list_entry(link, type, member) \
	((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))

static Usvr_Info *g_svrinfo = NULL;

static int usvr_get_symbol()
{
    static int usvr_symbol = 0;

    return usvr_symbol++;
}

void usvr_multicast(Usvr_Info *pinfo, int dev, unsigned char *package, int len)
{
    if (!package || !*package)
        return;

    Start_st *pheader = (Start_st *)package;
    pheader->ss_dev = pinfo->svr_dev;

    Usvr_Incoming *tmp;

    for (tmp = pinfo->list; tmp != NULL ; tmp = (Usvr_Incoming *) (tmp->hh.next))
    {
        if (tmp->ui_dev != dev)
        {       
            usocket_send(tmp->ui_fd, package, len);
        }
    }    
}

void usvr_append_incomingsocket(Usvr_Incoming **pplist, int sockfd)
{
	Usvr_Incoming *p = NULL;
	HASH_FIND_INT(*pplist, &sockfd, p);
	if (!p)
    {
        p = (Usvr_Incoming *)malloc(sizeof(Usvr_Incoming));
        memset(p, 0, sizeof(Usvr_Incoming));
        p->ui_fd = sockfd;
        HASH_ADD_INT(*pplist, ui_fd, p);
    }	
}

void usvr_remove_incomingsocket(Usvr_Incoming **pplist, int sockfd)
{
	Usvr_Incoming *pnode = NULL;
    HASH_FIND_INT(*pplist,&sockfd,pnode);	
    if (pnode)
    {
		HASH_DEL(*pplist, pnode);
        close(sockfd);
        free(pnode);
        pnode = NULL;
    }	
}

void usvr_refresh_incominginfo(Usvr_Incoming **pplist, int sockfd, int dev)
{
	Usvr_Incoming *p = NULL;
	HASH_FIND_INT(*pplist, &sockfd, p);
	if (p)
    {
        p->ui_dev = dev;
    }	
}

static int usvr_parse_package_cb(void *pvinfo, int sockfd)
{
	int ret;
    Start_st startheader;
    unsigned char endcode;
	
	if (!pvinfo)
		return -1;
	
	Usvr_Info *pinfo = (Usvr_Info *)pvinfo;

    ret = usocket_recv(sockfd, &startheader, sizeof(Start_st));
	if (ret <= 0)
		goto bail1;

    if (USOCK_START_CODE != startheader.startcode)
        goto bail1;

    int package_len = sizeof(startheader) + startheader.ss_len + sizeof(endcode);
    
	unsigned char *package = (unsigned char *)malloc(package_len);
    char *pdata = (char *)(package + sizeof(startheader));

	ret = usocket_recv(sockfd, pdata, startheader.ss_len);
	if (ret <= 0)
		goto bail2;	

	ret = usocket_recv(sockfd, &endcode, sizeof(endcode));
	if (ret <= 0)
		goto bail2;

	if (USOCK_END_CODE != endcode)
		goto bail2;

    memcpy(package, &startheader, sizeof(startheader));
    package[sizeof(startheader) + startheader.ss_len] = endcode;

    usvr_refresh_incominginfo(&pinfo->list, sockfd, startheader.ss_dev);
    
    usvr_multicast(pinfo, startheader.ss_dev, package, package_len);
    
    pdata[startheader.ss_len] = '\0';
	umsg_parse_json_handle2(startheader.ss_type, pdata, pinfo->uc_mcb);

    if (package)
	{
		free(package);    
        package = NULL;
	}

    return package_len;
	
bail2:
	if (package)
	{
		free(package);    
        package = NULL;
	}
bail1:
	return -1;		
}

void *usvr_accept_handle(void *p)
{
    fd_set readfds;
    int ret, sockfd, cnfd, maxfd;
    Usvr_Incoming *tmp;
	printf("usocket_accept_handle\n");
	
	if (!p)
		return NULL;
	
	Usvr_Info *psvr = (Usvr_Info *)p;

    sockfd = usocket_listen(psvr->path);
    psvr->svr_fd = sockfd;

    maxfd = sockfd;

    for (;;)
    {
        FD_ZERO(&readfds); 
        FD_SET(sockfd, &readfds);
        for (tmp = psvr->list; tmp != NULL ; tmp = (Usvr_Incoming *) (tmp->hh.next))
        {
            FD_SET(tmp->ui_fd, &readfds);
        }

        ret = select(maxfd + 1, &readfds, NULL, NULL, NULL);
        if (0 == ret)
        {
            continue;
        }
        else if (-1 == ret)
        {
            perror ("select error: ");
            return NULL;
        }
        else
        {
            if (FD_ISSET(sockfd, &readfds)) 
            {                        
                cnfd = usocket_accept(sockfd);
                if (-1 != cnfd) 
                {					
					usvr_append_incomingsocket(&psvr->list, cnfd);
                    printf("usvr_accept_handle cnfd = %d\n", cnfd);

                    if (cnfd > maxfd)
                        maxfd = cnfd;
                }
				else
				{
					return NULL;
				}
            }   

            for (tmp = psvr->list; tmp != NULL ; tmp = (Usvr_Incoming *) (tmp->hh.next))
            {
                if (FD_ISSET(tmp->ui_fd, &readfds))
                {
                    int ret;
                    ret = psvr->uc_cb(psvr, tmp->ui_fd);
                    if (ret <= 0)
                    {
                        fprintf(stderr, "recv error:%s\n", strerror(errno));
                        usvr_remove_incomingsocket(&psvr->list, tmp->ui_fd);
                    }
                }
            }
            
        }
    }

    return NULL;
}

int usvr_create2(const char *path, int dev, svr_parse_cb cb, svr_msg_cb mcb)
{
    if (!path || !*path)
        return -1;
    
	Usvr_Info *p = (Usvr_Info *)malloc(sizeof(Usvr_Info));
    memset(p, 0, sizeof(Usvr_Info));
    p->path = strdup(path);
    p->svr_dev = dev;
    p->us_symbol = usvr_get_symbol();
    
    if (cb)
	    p->uc_cb = cb;
    else
        p->uc_cb = usvr_parse_package_cb;

    if (mcb)
        p->uc_mcb = mcb;
        
    HASH_ADD_INT(g_svrinfo, us_symbol, p);
    create_thread(usvr_accept_handle, p, PTHREAD_STACK_MIN);
    return p->us_symbol;
}

int usvr_create(const char *path, int dev, svr_parse_cb cb)
{
    return usvr_create2(path, dev, cb, NULL);
}
/*
int main()
{
	return 0;
}
*/